package com.apes.fn.scm.income;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.crm.customerExpand.FnCustomerExpand;
import com.apes.fn.fico.expense.Expense;
import com.apes.fn.fico.expense.ExpenseItem;
import com.apes.fn.scm.internal.help.repository.InternalHelpReturnApprovalRepository;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.model.RetailOrderItem;
import com.apes.fn.scm.retailOrder.repository.RetailOrderItemRepository;
import com.apes.fn.scm.retailOrder.repository.RetailOrderRepository;
import com.apes.fn.scm.retailReturn.RetailReturnItem;
import com.apes.fn.scm.retailReturn.RetailReturnItemRepository;
import com.apes.fn.server.servicePlan.model.ServicePlan;
import com.apes.fn.server.servicePlan.repository.ServicePlanRepository;
import com.apes.fn.server.workOrder.model.MaintenanceOrder;
import com.apes.fn.server.workOrder.repository.MaintenanceOrderRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.LogicalUtil;
import com.apes.framework.util.MapUtil;
import com.apes.scm.account.account.model.Cooperation;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.account.tax.repository.TaxRepository;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.income.model.Income;
import com.apes.scm.income.model.IncomeItem;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.finance.model.IncomeType;
import com.apes.scm.masterdata.finance.repository.IncomeTypeRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.repository.VoucherRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @Title: SupplierPlatformFnService
 * @Description:
 * @author: ZhengZeXian
 * @create: 2022/6/10 13:56
 */
@Service("supplierPlatformFnService")
public class SupplierPlatformFnService extends DomainService {

    @Autowired
    private VoucherRepository voucherRepository;
    @Autowired
    private IncomeTypeRepository incomeTypeRepository;
    @Autowired
    private EnumerationRepository enumerationRepository;
    @Autowired
    private TaxRepository taxRepository;
    @Autowired
    private MaintenanceOrderRepository maintenanceOrderRepository;
    @Autowired
    private RetailOrderItemRepository retailOrderItemRepository;


    /**
     * 外协派工集群空间类型生成供应商收入单和平台费用单
     * @param wrapper
     */
    @OutboxSubscriber(id = "local.SupplierPlatformFnService.createIncomeAndExpense", name = "外协派工集群空间类型生成供应商收入单和平台费用单")
    public void createIncomeAndExpense(OutboxPayloadWrapper wrapper){
        JSONObject reqBody = (JSONObject)JSONObject.parse(wrapper.getPayload());
        Contract contract = MapUtil.getO(reqBody.getJSONObject("contract"), Contract.class);
        JSONArray array = reqBody.getJSONArray("maintenanceOrders");
        if (array.size() == 0) return;
        List<MaintenanceOrder> maintenanceOrders =  array.stream().map(tempJson -> MapUtil.getO(tempJson, MaintenanceOrder.class)).collect(Collectors.toList());
            workOutHelp(contract,maintenanceOrders,wrapper.getAggregateId());
    }

    /**
     * 冲红外协派工集群空间类型生成负的供应商收入单和平台费用单
     * @param wrapper
     */
    @OutboxSubscriber(id = "local.SupplierPlatformFnService.createReturnIncomeAndExpense", name = "冲红时外协派工集群空间类型生成负的供应商收入单和平台费用单")
    public void createReturnIncomeAndExpense(OutboxPayloadWrapper wrapper){
        JSONObject reqBody = (JSONObject)JSONObject.parse(wrapper.getPayload());
        Contract contract = MapUtil.getO(reqBody.getJSONObject("contract"), Contract.class);
        JSONArray array = reqBody.getJSONArray("retailReturnItems");
        if (array.size() == 0) return;
        List<RetailReturnItem> retailReturnItems =  array.stream().map(tempJson -> MapUtil.getO(tempJson, RetailReturnItem.class)).collect(Collectors.toList());
        // serverOutHelpReturn 指工单外协（经销）经销带安退货  retailOutHelpReturn 指的是外协代销带安 代销带安退货
        if (Objects.equals("serverOutHelpReturn", reqBody.get("type"))) {
            serverOutHelpReturn(contract,retailReturnItems);
        }else {
            retailOutHelpReturn(contract,retailReturnItems);
        }
    }

    private void workOutHelp(Contract contract, List<MaintenanceOrder> maintenanceOrders, String aggregateId){
        // 获取第一行的数据
        MaintenanceOrder workOrder = maintenanceOrders.get(0);

        PartyRole company ;      // 公司
        PartyRole platform = workOrder.getPlatform();    // 平台
        PartyRole supplier;//供应商

        // 获取方案数据
        ServicePlan servicePlan = workOrder.getServicePlanItem().getServicePlan();
        FnCustomerExpand fnCustomerExpand = servicePlan.getFnCustomerExpand();
        String servicePlanId = servicePlan.getId();

//        if ("supplier".equals(contract.getContractType().getCode()) && !Objects.equals(contract.getCompany().getId(), company.getId())) {
//            // 找合同上面的所属公司做采购
//            supplier = contract.getCompany().getParty().getPartyRoleByType("Supplier");
//        } else {
//            // 直接找供应商做采购
            supplier = maintenanceOrders.get(0).getSupplier();
//        }
        Enumeration operation = workOrder.getCompany().getParty().getCorporate().getOperation();
        if ("001073".equals(operation.getId())) {
            // 赋能店的公司 为1007
            company = SpringManager.getBean(PartyRoleRepository.class).findOne("1007");
        } else{
            // 非赋能店的公司取值为 1001
            company = SpringManager.getBean(PartyRoleRepository.class).findOne("1001");
        }

        Voucher voucher = voucherRepository.findOne(aggregateId);
        Optional.ofNullable(voucher).orElseThrow( () -> new RuntimeException("未找到对应的采购凭证，请检查"));

        String type = Objects.equals("1007", platform.getId()) ? "A08" : "A07";
        IncomeType incomeType = incomeTypeRepository.findOne(type);
        IncomeType expenseType = incomeTypeRepository.findOne("G16");

        Date createDate = voucher.getCreateDate();
        Set<IncomeItem> incomeItems = new HashSet<IncomeItem>();
        List<ExpenseItem> expenseItems = new ArrayList<>();
        AtomicReference<Boolean> tag = new AtomicReference<>(false);
        AtomicReference<Boolean> tag1 = new AtomicReference<>(false);

        voucher.getVoucherItems().forEach(voucherItem -> maintenanceOrders.forEach(maintenanceOrder -> {
            if (!voucherItem.getProduct().getId().equals(maintenanceOrder.getProduct().getId())) return;
            double siteFee = maintenanceOrder.getSiteFee();
            double platFee = maintenanceOrder.getPlatFee();
            //场地费加平台费不等于0生成收入单
            if (siteFee + platFee == 0 ) return;
            tag.set(true);
            if(SpringManager.getBean(InternalHelpReturnApprovalRepository.class).findOne(voucher.getOrigin()) != null){
                siteFee = siteFee * -1;
                platFee = platFee * -1;
            }
            //如果是1007 公司税率为无税 1001则为13%税率
            Tax tax = taxRepository.findOne(Long.valueOf(Objects.equals("1007", platform.getId()) ? 5 : 6));
            incomeItems.add(builderIncomeItem(incomeType,siteFee+platFee,createDate,
                    String.format("[%s] %s ",voucherItem.getProduct().getId(),voucherItem.getProduct().getName()),tax));

            // 场地费不等于0生成费用单
            if (siteFee == 0) return;
            tag1.set(true);
            PartyRole expenseCompany = maintenanceOrder.getBelongDept().getCompany();
            if(LogicalUtil.in("1001",platform.getId(),expenseCompany.getId())) return;
            ServicePlan plan = maintenanceOrder.getServicePlanItem().getServicePlan();
            String dept = "";
            if(!plan.getServiceDept().getId().equals(plan.getSaleDept().getId())) dept = plan.getSaleDept().getName();
            expenseItems.add(builderExpenseItem(expenseCompany,expenseType,siteFee * -1, createDate,
                    String.format("集群空间自动创建费用单/车牌：%s/服务方案单号：%s/接车门店：%s",
                            maintenanceOrder.getFnCustomerExpand().getCarLicense(), servicePlanId,dept)));

        }));
        if (tag.get()) builderIncome(company, supplier, voucher.getId(), servicePlanId, contract.getCooperation(), incomeItems, fnCustomerExpand.getId(), fnCustomerExpand.getCarLicense());
        if (tag1.get()&&expenseItems.size()>0) builderExpense(platform, expenseItems);
    }

    private ServicePlan workOutFindPlan(Voucher voucher) {
        String businessType = voucher.getOriginBusinessType();
        String source = voucher.getOrigin();
        if (source==null) return null;
        ServicePlan servicePlan=null;
        if (businessType.equals("RetailOrder")) {
            RetailOrder retailOrder = SpringManager.getBean(RetailOrderRepository.class).findOne(source);
            if (retailOrder.getSource()==null) return null;
            servicePlan = SpringManager.getBean(ServicePlanRepository.class).findOne(retailOrder.getSource());
        }
        if (businessType.equals("ServicePlan")){
            servicePlan = SpringManager.getBean(ServicePlanRepository.class).findOne(source);
        }

        if (servicePlan==null) return null;
        return servicePlan;
    }


    private void retailOutHelpReturn(Contract contract, List<RetailReturnItem> retailReturnItems){
        //需要重新查询一遍否则 order为空
        RetailReturnItem item = SpringManager.getBean(RetailReturnItemRepository.class).findOne(retailReturnItems.get(0).getId());
        RetailOrder retailOrder = retailOrderItemRepository.findOne(retailReturnItems.get(0).getRetailOrderItem().getId()).getOrder();
        PartyRole company = retailOrder.getCompany();
        PartyRole platform = retailReturnItems.get(0).getRetailOrderItem().getPlatform();
        String servicePlanId = retailOrder.getSource();
        FnCustomerExpand customerExpand = retailOrder.getCustomerExpand();
        PartyRole supplier;
        if ("supplier".equals(contract.getContractType().getCode()) && !Objects.equals(contract.getCompany().getId(), company.getId())) {
            // 找合同上面的所属公司做采购
            supplier = contract.getCompany().getParty().getPartyRoleByType("Supplier");
        } else {
            // 直接找供应商做采购
            supplier = contract.getPartner().getParty().getPartyRoleByType("Supplier");
        }

        //根据公司和合作伙伴和源单据找到供应商采购凭证
        Voucher voucher = voucherRepository.findPurchaseVoucherByCompanyAndOriginAndItemId(company, supplier, item.getOrder().getId(), item.getId());
        String type = Objects.equals("1007", platform.getId()) ? "A08" : "A07";
        IncomeType incomeType = incomeTypeRepository.findOne(type);
        IncomeType expenseType = incomeTypeRepository.findOne("G16");

        Date createDate = voucher.getCreateDate();
        Set<IncomeItem> incomeItems = new HashSet<IncomeItem>();
        List<ExpenseItem> expenseItems = new ArrayList<>();
        AtomicReference<Boolean> tag = new AtomicReference<>(false);
        AtomicReference<Boolean> tag1 = new AtomicReference<>(false);
        voucher.getVoucherItems().forEach(voucherItem -> {
            String sourceId = voucherItem.getSourceItemId();

            retailReturnItems.forEach( retailReturnItem -> {
                RetailOrderItem retailOrderItem = retailReturnItem.getRetailOrderItem();

                if (!sourceId.equals(retailReturnItem.getId())) return;

                //查询工单
                MaintenanceOrder maintenanceOrder = maintenanceOrderRepository.findFirstByServicePlanItemIdAndBusinessTypeNotIn(retailOrderItem.getOriginnumber(), Arrays.asList("out"));

                //场地费加平台费不等于0生成收入单
                if (maintenanceOrder.getSiteFee() + maintenanceOrder.getPlatFee() == 0 ) return;

                tag.set(true);

                // 构造供应商收入单明细数据
                //如果是1007 公司税率为无税 1001则为13%税率
                Tax tax = taxRepository.findOne(Long.valueOf(Objects.equals("1007", platform.getId()) ? 5 : 6));
                incomeItems.add(builderIncomeItem(incomeType,(maintenanceOrder.getSiteFee()+maintenanceOrder.getPlatFee()) * -1,createDate,
                        String.format("[%s] %s ",voucherItem.getProduct().getId(),voucherItem.getProduct().getName()),tax));

                // 场地费不等于0生成费用单
                if (maintenanceOrder.getSiteFee() == 0) return;
                tag1.set(true);
                PartyRole expenseCompany = maintenanceOrder.getBelongDept().getCompany();
                if(LogicalUtil.in("1001",platform.getId(),expenseCompany.getId())) return;
                ServicePlan plan = maintenanceOrder.getServicePlanItem().getServicePlan();
                String dept = "";
                if(!plan.getServiceDept().getId().equals(plan.getSaleDept().getId())) dept = plan.getSaleDept().getName();
                expenseItems.add(builderExpenseItem(expenseCompany,expenseType,maintenanceOrder.getSiteFee(), createDate,
                        String.format("集群空间自动创建费用单/车牌：%s/服务方案单号：%s/接车门店：%s",
                                maintenanceOrder.getFnCustomerExpand().getCarLicense(), servicePlanId,dept)));
            });
        });
        if (tag.get()) builderIncome(platform,supplier,voucher.getId(),servicePlanId,contract.getCooperation(),incomeItems, customerExpand.getId(),customerExpand.getCarLicense());
        if (tag1.get()) builderExpense(platform,expenseItems);
    }

    private void serverOutHelpReturn(Contract contract, List<RetailReturnItem> retailReturnItems){
        //需要重新查询一遍否则 order为空
        RetailReturnItem item = SpringManager.getBean(RetailReturnItemRepository.class).findOne(retailReturnItems.get(0).getId());
        RetailOrder retailOrder = retailOrderItemRepository.findOne(retailReturnItems.get(0).getRetailOrderItem().getId()).getOrder();
        PartyRole company = retailOrder.getCompany();
        PartyRole platform = retailReturnItems.get(0).getRetailOrderItem().getPlatform();
        String servicePlanId = retailOrder.getSource();
        FnCustomerExpand customerExpand = retailOrder.getCustomerExpand();
        PartyRole supplier;
        if ("supplier".equals(contract.getContractType().getCode()) && !Objects.equals(contract.getCompany().getId(), company.getId())) {
            // 找合同上面的所属公司做采购
            supplier = contract.getCompany().getParty().getPartyRoleByType("Supplier");
        } else {
            // 直接找供应商做采购
            supplier = contract.getPartner().getParty().getPartyRoleByType("Supplier");
        }

        //根据公司和合作伙伴和源单据找到供应商采购凭证
        Voucher voucher = voucherRepository.findPurchaseVoucherByCompanyAndOriginAndItemId(company, supplier, item.getOrder().getId(), item.getId());
        String type = Objects.equals("1007", platform.getId()) ? "A08" : "A07";
        IncomeType incomeType = incomeTypeRepository.findOne(type);
        IncomeType expenseType = incomeTypeRepository.findOne("G16");

        Date createDate = voucher.getCreateDate();
        Set<IncomeItem> incomeItems = new HashSet<IncomeItem>();
        List<ExpenseItem> expenseItems = new ArrayList<>();
        AtomicReference<Boolean> tag = new AtomicReference<>(false);
        AtomicReference<Boolean> tag1 = new AtomicReference<>(false);

        voucher.getVoucherItems().forEach(voucherItem -> {
            String sourceId = voucherItem.getSourceItemId();

            retailReturnItems.forEach( retailReturnItem -> {
                RetailOrderItem retailOrderItem = retailReturnItem.getRetailOrderItem();

                if (!sourceId.equals(retailReturnItem.getId())) return;

                //查询工单
                MaintenanceOrder maintenanceOrder = maintenanceOrderRepository.findFirstByServicePlanItemIdAndBusinessTypeNotIn(retailOrderItem.getOriginnumber(), Arrays.asList("out"));

                //场地费加平台费不等于0生成收入单
                if (maintenanceOrder.getSiteFee() + maintenanceOrder.getPlatFee() == 0 ) return;
                tag.set(true);
                // 构造供应商收入单明细数据
                //如果是1007 公司税率为无税 1001则为13%税率
                Tax tax = taxRepository.findOne(Long.valueOf(Objects.equals("1007", platform.getId()) ? 5 : 6));
                incomeItems.add(builderIncomeItem(incomeType,(maintenanceOrder.getSiteFee()+maintenanceOrder.getPlatFee()) * -1,createDate,
                        String.format("[%s] %s ",voucherItem.getProduct().getId(),voucherItem.getProduct().getName()),tax));

                // 场地费不等于0生成费用单
                if (maintenanceOrder.getSiteFee() == 0) return;
                tag1.set(true);
                PartyRole expenseCompany = maintenanceOrder.getBelongDept().getCompany();
                if(LogicalUtil.in("1001",platform.getId(),expenseCompany.getId())) return;
                ServicePlan plan = maintenanceOrder.getServicePlanItem().getServicePlan();
                String dept = "";
                if(!plan.getServiceDept().getId().equals(plan.getSaleDept().getId())) dept = plan.getSaleDept().getName();
                expenseItems.add(builderExpenseItem(expenseCompany,expenseType,maintenanceOrder.getSiteFee(), createDate,
                        String.format("集群空间自动创建费用单/车牌：%s/服务方案单号：%s/接车门店：%s",
                                maintenanceOrder.getFnCustomerExpand().getCarLicense(), servicePlanId,dept)));
            });
        });
        if (tag.get()) builderIncome(platform,supplier,voucher.getId(),servicePlanId,contract.getCooperation(),incomeItems,customerExpand.getId(),customerExpand.getCarLicense());
        if (tag1.get()) builderExpense(platform,expenseItems);
    }


    /**
     * 封装供应商收入单
     * @param company 公司
     * @param partner 合作伙伴 供应商
     * @param source 来源单据号
     * @param origin 源单据号
     * @param itemSet 供应商收入单明细
     */
    private void builderIncome(PartyRole company, PartyRole partner, String source, String origin, Cooperation cooperation,Set<IncomeItem> itemSet,String fnCustomerExpand,String carLicense) {

        //如果是1007 公司税率为无税 1001则为13%税率
        int id = Objects.equals("1007", company.getId()) ? 5 : 6;
        //如果是1007 收入类别为cost（费用） 1001则为rebate（返利）
        String incomeName = Objects.equals("1007", company.getId()) ? "cost" : "rebate";
        Enumeration siteUseFee = enumerationRepository.findOne(incomeName);

        Tax tax = taxRepository.findOne(Long.valueOf(id));

        Income income = new Income();
        income.setCompany(company);
        income.setPartner(partner);
        income.setFnCustomerExpand(fnCustomerExpand);
        income.setCarLicense(carLicense);
        income.setInComeCategory(siteUseFee);
        income.setCooperation(cooperation);
        income.setSource(source);
        income.setOrigin(origin);
        income.setNote("集群空间自动创建返利");
        income.setCreator("system");
        income.setUserId("0");
        income.setIncomeItems(itemSet);

        this.invoke("income.supplier.approveBySystem",MapUtil.mapped(this.invoke("income.supplier.createBySystem", MapUtil.mapped(income))));

    }

    private IncomeItem builderIncomeItem(IncomeType incomeType,Double amount,Date businessDate,String note, Tax tax){
        IncomeItem item = new IncomeItem();
        item.setIncomeType(incomeType);
        item.setIncomeAmount(amount);
        item.setStartDate(businessDate);
        item.setEndDate(businessDate);
        item.setNote(note);
        item.setDone(false);
        item.setTax(tax);
        return item;
    }

    private void builderExpense(PartyRole company,List<ExpenseItem> items){
        Expense expense = new Expense();
        expense.setCompany(company);
        expense.setExpenseItems(items);
        expense.setCreator("system");
        expense.setUserId("0");
        this.invoke("fn.expense.approveBySystem",MapUtil.mapped(this.invoke("fn.expense.create", MapUtil.mapped(expense))));
    }

    private ExpenseItem builderExpenseItem(PartyRole company, IncomeType expenseType, Double amount, Date businessDate, String note) {
        ExpenseItem item = new ExpenseItem();
        item.setCompany(company);
        item.setExpenseType(expenseType);
        item.setAmount(amount);
        item.setPeriodStart(businessDate);
        item.setPeriodEnd(businessDate);
        item.setRemark(note);
        return item;
    }



}
